#include "Decrypter.h"

void get_md5(unsigned char *input, unsigned char *output) {
	int i;
	MD5_CTX contexto;
	unsigned char *buffer = (unsigned char *) malloc(17);
	MD5_Init(&contexto);
	MD5_Update(&contexto, input, strlen((char*) input));
	MD5_Final(buffer, &contexto);
	*output = 0;
	for (i = 0; i < 16; i++) {
		sprintf((char*) output, "%s%02x", (char*) output, buffer[i]);
	}
}

void incrementPassword(unsigned char actualPassword[], int passwordLength) {
	actualPassword[0] = actualPassword[0] + 1;
	int i;
	/* Se consideran solo caracteres imprimibles */
	for (i = 0; i < passwordLength - 1; i++) {
		if (actualPassword[i] > 126) {
			actualPassword[i] = 32;
			actualPassword[i + 1] = actualPassword[i + 1] + 1;
		}
	}
}

int bruteForce(unsigned char encryptedPassword[], int passwordLength,
		unsigned char salt[], int saltMode, unsigned char result[]) {
	int passwordFound = 0; /* Se pone en 1 cuando se logro matchear una pass */
	unsigned char actualPassword[MAX_PWD_LENGTH+1]; /*Aca vamos a ir probando las pass, suponemos un maximo de passwds de 32 bytes*/
	unsigned char md5Buffer[MD5_LENGTH+1];
	memset(md5Buffer, 0, MD5_LENGTH+1);
	int j;
	/* Inicializo en el primer caracter imprimible */
	for (j = 0; j < passwordLength; j++) {
		actualPassword[j] = FIRST_PRINTABLE_CHARACTER;
	}
	actualPassword[passwordLength] = 0;

	if (saltMode == 1) {
		int saltLength = strlen((char*) salt);
		/* ultimos 2 bytes son fijos : la salt */
		actualPassword[passwordLength - 2] = salt[0];
		actualPassword[passwordLength - 1] = salt[1];
		passwordLength -= saltLength; /* Despues lo trato como una de los (salt-length) caracteres restantes */
	}

	while (passwordFound == 0) {
		get_md5(actualPassword, md5Buffer);
		passwordFound = (strcmp((char*) md5Buffer, (char*) encryptedPassword)
				== 0);
		if (passwordFound == 1) {
			strcpy((char*) result, (char*) actualPassword);
			break;
		} else {
			incrementPassword(actualPassword, passwordLength);
			if (actualPassword[passwordLength - 1] > LAST_PRINTABLE_CHARACTER) {
				break;
			}
		}
	}
	return passwordFound; /* Devuelve 0 si no logro desencriptar */
}
